<template>

  
  <nav class="top-menu">
    <div><span style="margin-left:10px;font-weight: bold;font-size:20px">{{ siteName }}</span></div>
    <ul>
      <li v-for="item in topMenus" :key="item.id" :class="{ active: activeTop === item.name }" @click="select(item)">
        {{ item.name }}
      </li>
    </ul>
    <div class="right">
      <el-icon style="color:#fff"><User /></el-icon><span v-if="user" style="font-size:14px">{{ userRole }}: {{ user.username }}</span>
      <!-- use Element Plus dropdown for the user actions -->
      <el-dropdown v-if="isAuthenticated" @command="handleCommand" trigger="click">
        <span style="cursor: pointer; color:#fff; display:inline-flex; align-items:center; padding:4px 8px;">        
          <el-icon style="color:#fff"><MoreFilled /></el-icon>    
        </span>
        <template #dropdown>
          <el-dropdown-menu>
            <el-dropdown-item command="resetPwd">密码修改</el-dropdown-item>
            <el-dropdown-item command="logout">退出登录</el-dropdown-item>
          </el-dropdown-menu>
        </template>
      </el-dropdown>
    </div>
  </nav>

  <!-- password reset dialog -->
  <el-dialog v-model="resetDialogVisible" title="修改密码" width="420px" :close-on-click-modal="false">
    <el-form label-position="top" :model="resetForm">
      <el-form-item label="旧密码">
        <el-input v-model="resetForm.oldPwd" type="password" show-password @blur="verifyOldPwd" />
        <div v-if="oldPwdStatus==='checking'" style="color:#999;margin-top:6px;">校验中...</div>
        <div v-if="oldPwdStatus==='invalid'" style="color:#f56c6c;margin-top:6px;">{{ oldPwdError }}</div>
      </el-form-item>
      <el-form-item label="新密码">
        <el-input v-model="resetForm.newPwd" type="password" show-password />
      </el-form-item>
      <el-form-item label="确认新密码">
        <el-input v-model="resetForm.confirmPwd" type="password" show-password />
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button @click="resetDialogVisible = false">取消</el-button>
      <el-button type="primary" :loading="submitting" @click="submitReset">确定</el-button>
    </template>
  </el-dialog>

</template>

<script setup lang="ts">
import { computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useMenuStore } from '../stores/menu'
import { useAuthStore } from '../stores/auth'
import { storeToRefs } from 'pinia'
// import the Menu icon component so <Menu /> works in the template
import { User } from '@element-plus/icons-vue'
import { MoreFilled } from '@element-plus/icons-vue'
import { ref, watch, reactive } from 'vue'
import { ElMessage } from 'element-plus'
const router = useRouter()
const menu = useMenuStore()
const auth = useAuthStore()
const { activeTop } = storeToRefs(menu)
const { user, isAuthenticated, menus } = storeToRefs(auth)

const siteName = ref('安顺市精神卫生平台V1.0')

async function loadSiteName() {
  try {
    // use public endpoint that doesn't require Authorization header
    const res = await fetch('/public/site-name')
    if (!res.ok) return
    const body = await res.json().catch(() => ({}))
    if (body && body.value) {
      siteName.value = body.value
    }
  } catch (e) {
    // fallback to default site name
  }
}

onMounted(() => {
  loadSiteName()
  // initialize sidebar visibility based on the current active top menu
  updateSidebarForTop(activeTop.value)
})

// derive a displayable role name from common user properties

const userRole = ref('')

async function resolveUserRole(u: any) {
  const uu = u && (u.value ?? u)
  if (!uu) { userRole.value = ''; return }

  // prefer directly available names
  if (typeof uu.role_name === 'string' && uu.role_name) { userRole.value = uu.role_name; return }
  if (typeof uu.role === 'string' && uu.role) { userRole.value = uu.role; return }
  if (uu.role && typeof uu.role === 'object' && (uu.role.name || uu.role.role_name)) {
    userRole.value = uu.role.name || uu.role.role_name
    return
  }

  // if we only have a role_id, try to fetch the role record from the auth store (try several common method names)
  const roleId = uu.role_id ?? (uu.role && uu.role.id)
  if (roleId == null) { userRole.value = ''; return }

  const candidates = ['fetchRole','fetchRoleById','getRole','getRoleById','fetchRoleName','getRoleName']
  for (const fn of candidates) {
    const fnRef = (auth as any)[fn]
    if (typeof fnRef !== 'function') continue
    try {
      const res = await fnRef(roleId)
      if (!res) continue
      // common shapes: string, { role_name }, { name }, { data: { ... } }
      if (typeof res === 'string') { userRole.value = res; return }
      if (res.role_name) { userRole.value = res.role_name; return }
      if (res.name) { userRole.value = res.name; return }
      if (res.data && (res.data.role_name || res.data.name)) {
        userRole.value = res.data.role_name || res.data.name
        return
      }
    } catch {
      /* ignore and try next candidate */
    }
  }

  // final fallback: show the raw id
  userRole.value = `角色${roleId}`
}

watch(user, () => resolveUserRole(user), { immediate: true })

// helper to recursively remove function-type items
function removeFunctionItems(items: any[]) {
  return items
    .filter((item) => item.is_function !== 1)
    .map((item) => ({
      ...item,
      children: item.children ? removeFunctionItems(item.children) : undefined,
    }))
}

const topMenus = computed(() => removeFunctionItems(menus.value || []))

// helper to set sidebar safely (prefers store method if present)
function setSidebar(visible: boolean) {
  if (menu && typeof (menu as any).setShowSidebar === 'function') {
    ;(menu as any).setShowSidebar(visible)
  } else if (menu) {
    try { (menu as any).showSidebar = visible } catch (e) { /* ignore */ }
  }
}

// update the sidebar visibility based on whether the given top menu (by name) has any visible children
async function updateSidebarForTop(name: string) {
  try {
    // find the menu object by name from in-memory menus
    const candidate = (menus.value || []).find((m: any) => m.name === name)
    if (candidate) {
      const localChildren = removeFunctionItems(candidate.children || [])
      if (localChildren && localChildren.length > 0) {
        setSidebar(true)
        return
      }
      // try fetching children from server if no local children
      const rawId = candidate.id ?? null
      const pid = Number(rawId)
      if (!Number.isNaN(pid)) {
        try {
          const fetched = await auth.fetchChildren(pid)
          const fetchedFiltered = removeFunctionItems(fetched || [])
          setSidebar(!!(fetchedFiltered && fetchedFiltered.length > 0))
          return
        } catch (e) {
          // ignore and fall through
        }
      }
    }
  } catch (e) {
    // ignore
  }
  // default: hide sidebar when no children found
  setSidebar(false)
}

// ensure sidebar updates whenever activeTop changes (covers clicks and external changes such as route navigation)
watch(activeTop, (v) => {
  try { updateSidebarForTop(v) } catch (e) { /* ignore */ }
}, { immediate: true })

// also watch menus so that when they are fetched asynchronously we re-evaluate the sidebar
// e.g. on app refresh or login the menus may be loaded after main init; ensure sidebar visibility is updated
watch(menus, (newMenus) => {
  try {
    // only attempt update when menus appear to have content
    if (newMenus && (Array.isArray(newMenus) ? newMenus.length > 0 : Object.keys(newMenus).length > 0)) {
      updateSidebarForTop(activeTop.value)
    }
  } catch (e) { /* ignore */ }
}, { deep: true, immediate: true })

async function select(item: any) {
  menu.setActiveTop(item.name)
  // determine the id of the clicked top menu (use item.id if present, otherwise lookup by name)
  const rawId = item.id ?? (menus.value || []).find((m: any) => m.name === item.name)?.id
  const parentId = Number(rawId)
  // update sidebar visibility based on children
  // prefer to use fetched children if available
  if (!Number.isNaN(parentId)) {
    try {
      const children = await auth.fetchChildren(parentId)
      const visibleChildren = removeFunctionItems(children || [])
      const hasChildren = visibleChildren && visibleChildren.length > 0
      setSidebar(hasChildren)
      const target = (hasChildren && visibleChildren[0]?.url) || item.url || '/'
      router.push(target)
      return
    } catch (e) {
      // continue to fallback
    }
  }
  // fallback to existing children in memory or the item's url
  const localChildren = (item.children && item.children.length > 0 && removeFunctionItems(item.children)) || []
  const target = (localChildren && localChildren.length > 0 && localChildren[0]?.url) || item.url || '/'
  setSidebar(!!(localChildren && localChildren.length > 0))
  router.push(target)
}

function doLogout() {
  auth.logout()
  router.push('/login')
}

// password reset dialog state and actions
const resetDialogVisible = ref(false)
const resetForm = reactive({ oldPwd: '', newPwd: '', confirmPwd: '' })
const submitting = ref(false)
// verification state: 'idle' | 'checking' | 'valid' | 'invalid'
const oldPwdStatus = ref<'idle' | 'checking' | 'valid' | 'invalid'>('idle')
const oldPwdError = ref('')

async function verifyOldPwd() {
  // skip verification for admins
  const currentUser = user && (user.value ?? user)
 

  if (!resetForm.oldPwd) {
    oldPwdStatus.value = 'invalid'
    oldPwdError.value = '旧密码不能为空'
    return false
  }

  oldPwdStatus.value = 'checking'
  oldPwdError.value = ''
  try {
    const uid = (user && (user.value?.id ?? user.value?.user_id ?? user.value?.uid))
    if (!uid) throw new Error('无法读取当前用户ID')
    await auth.apiFetch(`/users/${uid}/verify-password`, { method: 'POST', body: JSON.stringify({ oldPwd: resetForm.oldPwd }) })
    oldPwdStatus.value = 'valid'
    oldPwdError.value = ''
    return true
  } catch (e) {
    oldPwdStatus.value = 'invalid'
    let msg = '旧密码不正确'
    try {
      if (e && typeof e.json === 'function') {
        const b = await e.json()
        if (b && b.message) msg = b.message
      } else if (e && e.message) msg = e.message
    } catch {}
    oldPwdError.value = msg
    return false
  }
}

function openResetDialog() {
  resetForm.oldPwd = ''
  resetForm.newPwd = ''
  resetForm.confirmPwd = ''
  oldPwdStatus.value = 'idle'
  oldPwdError.value = ''
  resetDialogVisible.value = true
}

async function submitReset() {
  if (!resetForm.newPwd || resetForm.newPwd.length < 6) {
    ElMessage.error('密码长度至少6位')
    return
  }
  if (resetForm.newPwd !== resetForm.confirmPwd) {
    ElMessage.error('两次输入的密码不一致')
    return
  }

  // if current user is not admin, require oldPwd and verify it
  const currentUser = user && (user.value ?? user)
  const ok = await verifyOldPwd()
    if (!ok) {
      ElMessage.error(oldPwdError.value || '旧密码验证失败')
      return
    }

  submitting.value = true
  try {
    const uid = (user && (user.value?.id ?? user.value?.user_id ?? user.value?.uid))
    if (!uid) throw new Error('无法读取当前用户ID')
    const body: any = { pwd: resetForm.newPwd }
    body.oldPwd = resetForm.oldPwd
    await auth.apiFetch(`/users/${uid}`, { method: 'PUT', body: JSON.stringify(body) })
    ElMessage.success('密码修改成功，请重新登录')
    resetDialogVisible.value = false
    // logout and redirect to login so user re-authenticates with new password
    auth.logout()
    router.push('/login')
  } catch (e) {
    let msg = '密码修改失败'
    try {
      if (e && typeof e.json === 'function') {
        const b = await e.json()
        if (b && b.message) msg = b.message
      } else if (e && e.message) msg = e.message
    } catch {}
    ElMessage.error(msg)
  } finally {
    submitting.value = false
  }
}

// extend handleCommand to handle resetPwd
function handleCommand(command: string) {
  if (command === 'logout') {
    doLogout()
  } else if (command === 'profile') {
    // navigate to a profile/settings page if available
    router.push('/settings')
  } else if (command === 'resetPwd') {
    openResetDialog()
  }
}
</script>

<style scoped>
.top-menu { background:#2d3a4b; color:#fff; display:flex; align-items:center; justify-content:space-between }
.top-menu ul { display:flex; gap:12px; list-style:none; margin:0; padding:10px 16px }
.top-menu li { cursor:pointer; padding:6px 12px; border-radius:4px }
.top-menu li.active { background:#e6f0ff;color:#e6a23c }
.top-menu .right { padding-right:12px; display:flex; gap:8px; align-items:center }
.top-menu button { background:transparent; border:1px solid rgba(255,255,255,0.2); color:#fff; padding:4px 8px; border-radius:4px }
</style>